import 'dart:convert';
import 'dart:io';
import 'dart:ui';

import 'package:devicelocale/devicelocale.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:mybaseplus/base/tool/empty/FFEmpty.dart';
import 'package:mybaseplus/base/tool/extension/FFListExt.dart';
import 'package:mybaseplus/base/tool/file/FFAssetFile.dart';
import 'package:mybaseplus/base/tool/file/FFile.dart';
import 'package:mybaseplus/base/tool/pprint/FFLog.dart';
import 'package:mybaseplus/base/tool/sp/FFSpUtils.dart';

abstract class FFMainAppState {
  onLanguageRefresh();
}

class FFMultiLanguage {
  static String SpLanguageCode = "SpLanguageCode";
  static FFMainAppState? state;

  ///找不到对应的语言时，默认语言
  static bool? fllowerSystem = true;
  static Locale defaultLocale = const Locale(LCODE_EN);
  static Locale apiLocale = defaultLocale;

  ///当前语言
  static Locale? currentLocale;

  ///语言代理类
  static Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates = [];

  ///支持的语言版本
  static List<LanguageConfigEntity> supportedLocalesList = [
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_EN),
        languageName: 'English'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_ZH, scriptCode: SCODE_HANS),
        languageName: '简体中文'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_ZH, scriptCode: SCODE_HANT),
        languageName: '繁體中文'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_DE),
        languageName: 'Deutsch'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_JA), languageName: '日本語'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_KO), languageName: '한국인'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_FR),
        languageName: 'Français'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_ES),
        languageName: 'español'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_IT),
        languageName: 'italiano'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_ID),
        languageName: 'bahasa Indonesia'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_RU),
        languageName: 'Русский'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_PT),
        languageName: 'Português'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_KK), languageName: 'қазақ'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_UK),
        languageName: 'українська'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_TH), languageName: 'แบบไทย'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_TR), languageName: 'Türkçe'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_PL), languageName: 'Polski'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_VI),
        languageName: 'Tiếng Việt'),
    LanguageConfigEntity(
        locale: const Locale.fromSubtags(languageCode: LCODE_HI), languageName: 'हिंदी'),
  ];

  static Iterable<Locale> supportedLocales() {
    List<Locale> list = [];
    for (int i = 0; i < supportedLocalesList.length; i++) {
      LanguageConfigEntity entity = supportedLocalesList[i];
      list.add(entity.locale);
    }
    return list;
  }

  ///MaterialApp的localeResolutionCallback回调，返回设置好的支持的语言中的一种
  static Locale mainSupportedLocales(Locale? locale) {
    if (locale == null) {
      return defaultLocale;
    }
    Locale? findLocale;
    var supportedList = supportedLocales();
    for (var element in supportedList) {
      if (element.languageCode == locale.languageCode) {
        if (locale.languageCode == LCODE_ZH) {
          ///中文
          //if (locale.scriptCode == SCODE_HANS || locale.countryCode == CCODE_CN) {
          bool hans = false; //true=简体
          if (!FFEmpty.stringIsEmpty(locale.scriptCode)) {
            if (locale.scriptCode == SCODE_HANS) {
              hans = true;
            }
          } else {
            if (!FFEmpty.stringIsEmpty(locale.countryCode)) {
              if (locale.countryCode == CCODE_CN) {
                hans = true;
              }
            }
          }

          if (hans == true) {
            //简体中文
            findLocale =
                const Locale.fromSubtags(languageCode: LCODE_ZH, scriptCode: SCODE_HANS);
            break;
          } else {
            //繁体中文
            findLocale =
                const Locale.fromSubtags(languageCode: LCODE_ZH, scriptCode: SCODE_HANT);
            break;
          }
        } else {
          findLocale = Locale.fromSubtags(languageCode: locale.languageCode);
          break;
        }
      }
    }

    if (findLocale != null) {
      // apiLocale = findLocale;
      return findLocale;
    }
    // apiLocale = defaultLocale;
    return defaultLocale;
  }

  ///初始化语言:取上次设置的语言，如果没有则默认系统语言
  static Future<void> initLanguage(FFMainAppState? appState) async {
    state ??= appState;
    String? code = FFSpUtils.getData(SpLanguageCode);
    if (!FFEmpty.stringIsEmpty(code)) {
      fllowerSystem = false;
      List<String> codeList = code!.split(CODELINE);
      if (FFEmpty.listIsEmpty(codeList)) {
        return;
      }
      if (codeList.length == 1) {
        currentLocale = Locale.fromSubtags(languageCode: codeList.first);
      } else if (codeList.length >= 2) {
        currentLocale =
            Locale.fromSubtags(languageCode: codeList[0], scriptCode: codeList[1]);
      }
      state?.onLanguageRefresh();
    } else {
      fllowerSystem = true;
    }
  }

  ///主动更改语言
  static Future<bool> changeLanguage(Locale locale) async {
    fllowerSystem = false;
    currentLocale = locale;
    apiLocale = currentLocale!;
    state?.onLanguageRefresh();

    if (FFEmpty.stringIsEmpty(locale.scriptCode)) {
      await FFSpUtils.saveData(SpLanguageCode, locale.languageCode);
    } else {
      await FFSpUtils.saveData(
          SpLanguageCode, "${locale.languageCode}$CODELINE${locale.scriptCode}");
    }

    return true;
  }

  static languageFllowerSystem() async {
    //跟随系统
    fllowerSystem = true;
    await FFSpUtils.remove(SpLanguageCode);
    Locale systemLocale = await deviceLanguage();
    currentLocale = null;
    apiLocale = systemLocale;
    state?.onLanguageRefresh();
  }

  /// 获取设备语言，获取不到时，使用默认语言
  static Future<Locale> deviceLanguage() async {
    String? defaultLocaleStr = await Devicelocale.defaultLocale;
    Locale? toLocale = localeStrToLocale(defaultLocaleStr);
    Locale realLocale = mainSupportedLocales(toLocale);
    return realLocale;
  }

  static Locale? localeStrToLocale(String? defaultLocaleStr) {
    /**
        简体
        zh-Hans-CN、zh-CN、zh

        繁体
        zh-Hant-xx、zh-TW

        英文
        en-xx
     */

    if (FFEmpty.stringIsEmpty(defaultLocaleStr)) {
      return defaultLocale;
    }
    List<String> list = defaultLocaleStr!.split(CODELINE);
    String? lCode = list.safeValue<String>(0) ?? "";
    String? code2 = list.safeValue<String>(1) ?? "";
    String? code3 = list.safeValue<String>(2) ?? "";

    if (lCode == LCODE_ZH) {
      //中文
      if (code2 == SCODE_HANS || code2 == CCODE_CN) {
        //简体
        return const Locale.fromSubtags(languageCode: LCODE_ZH, scriptCode: SCODE_HANS);
      } else {
        //繁体
        return const Locale.fromSubtags(languageCode: LCODE_ZH, scriptCode: SCODE_HANT);
      }
    } else {
      return Locale.fromSubtags(languageCode: lCode ?? LCODE_EN);
    }

    return defaultLocale;
  }

  //在接口header设置
  static getLang() {
    String languageCode = FFMultiLanguage.apiLocale.languageCode;

    if (languageCode == LCODE_EN) {
      //英文
      return "en-us";
    } else if (languageCode == LCODE_ZH) {
      //中文
      String? scriptCode = FFMultiLanguage.apiLocale.scriptCode;
      if (scriptCode == SCODE_HANT) {
        //繁体
        return "zh-tw";
      } else {
        //简体
        return "zh-cn";
      }
    } else {
      return languageCode;
    }

    return "en-us";
  }
}

///多语言类
class AppLocale {
  final Locale locale;
  dynamic language;

  AppLocale(this.locale, this.language);

  static AppLocaleDelegate? delegate;

  static AppLocale? of(BuildContext context) {
    return Localizations.of(context, AppLocale);
  }
}

///多语言代理类
class AppLocaleDelegate extends LocalizationsDelegate<AppLocale> {
  dynamic Function(
    Map<String, dynamic> json,
  ) onFuncCreateEntity;
  String languagePath;

  AppLocaleDelegate({
    required this.onFuncCreateEntity,
    required this.languagePath,
  });

  @override
  bool isSupported(Locale locale) {
    List<String> list = [];
    for (int i = 0; i < FFMultiLanguage.supportedLocalesList.length; i++) {
      LanguageConfigEntity entity = FFMultiLanguage.supportedLocalesList[i];
      if (!list.contains(entity.locale.languageCode)) {
        list.add(entity.locale.languageCode);
      }
    }
    return list.contains(locale.languageCode);
  }

  //加载自定义资源 转成Model
  @override
  Future<AppLocale> load(Locale locale) async {
    String? code = FFSpUtils.getData(FFMultiLanguage.SpLanguageCode);
    if (!FFEmpty.stringIsEmpty(code)) {
      FFMultiLanguage.fllowerSystem = false;
      List<String> codeList = code!.split(CODELINE);

      if (codeList.length == 1) {
        FFMultiLanguage.currentLocale = Locale.fromSubtags(languageCode: codeList.first);
      } else if (codeList.length >= 2) {
        FFMultiLanguage.currentLocale =
            Locale.fromSubtags(languageCode: codeList[0], scriptCode: codeList[1]);
      }

      locale = FFMultiLanguage.currentLocale!;
    } else {
      FFMultiLanguage.fllowerSystem = true;
    }

    String languageCode = locale.languageCode;
    String? scriptCode = locale.scriptCode;
    // FFLog.info("language load = $languageCode, scriptCode = $scriptCode");
    FFMultiLanguage.apiLocale = locale;

    String addScriptCode = "";
    if (!FFEmpty.stringIsEmpty(scriptCode)) {
      addScriptCode = "$CODELINE$scriptCode";
    }

    //读取本地配置
    File file = await FFAssetFile.fileByAsset(
        "$languagePath$languageCode$addScriptCode.json",
        "$languageCode$addScriptCode.json");
    String jsonStr = await FFile.readAsString(file.path);
    var map = json.decode(jsonStr);
    // FFLog.info("读取本地配置=${map.toString()}");
    dynamic languageEntity = onFuncCreateEntity(map);
    return SynchronousFuture<AppLocale>(AppLocale(locale, languageEntity));
  }

  @override
  bool shouldReload(LocalizationsDelegate<AppLocale> old) {
    return false;
  }
}

class LanguageConfigEntity {
  Locale locale;
  String languageName;

  LanguageConfigEntity({
    required this.locale,
    required this.languageName,
  });
}

const String CODELINE = "-";
const String CCODE_CN = "CN";

///中文
const String LCODE_ZH = "zh";

///英文
const String LCODE_EN = "en";

///德语
const String LCODE_DE = "de";

///日语
const String LCODE_JA = "ja";

///韩文
const String LCODE_KO = "ko";

///法语
const String LCODE_FR = "fr";

///西班牙
const String LCODE_ES = "es";

///意大利
const String LCODE_IT = "it";

///印度尼西亚语
const String LCODE_ID = "id";

///俄语
const String LCODE_RU = "ru";

///葡萄牙
const String LCODE_PT = "pt";

///哈萨克
const String LCODE_KK = "kk";

///乌克兰
const String LCODE_UK = "uk";

///泰语
const String LCODE_TH = "th";

///土耳其
const String LCODE_TR = "tr";

///波兰
const String LCODE_PL = "pl";

///越南语
const String LCODE_VI = "vi";

///印地语
const String LCODE_HI = "hi";

const String SCODE_HANS = "Hans";
const String SCODE_HANT = "Hant";
